package controllers

import (
	"net/http"
	"ServerGo/common"
	"os/exec"
	"io/ioutil"
	"github.com/bitly/go-simplejson"
	"strings"
	"os"
	"net/url"
	"strconv"
	"path/filepath"
	"mime/multipart"
	"time"
)

// @router /onlineResponse.php [Post]
// @binding controllers.EmptyParams
func OnlineResponse(params EmptyParams, res http.ResponseWriter, req *http.Request) string {
	if req.Form.Get("type") != "" && req.Form.Get("type") != "0" {
		md5Str := "db46d555cf435a8ec701e7ed7cec422d"

		if (req.Form.Get("token") != md5Str) {
			var errInfo string = "upload to online server TOKEN ERROR"
			common.Logger(common.LOG_WARNING, errInfo)
			return common.Object2JsonStr(ResponseMsg{2, errInfo, nil})

		}else if (req.Form.Get("type") == "1") {
			cmd := exec.Command("/bin/sh", "-c", "cd "+BUILD_PATH+" && git pull")
			output, err := cmd.CombinedOutput()

			if err != nil {
				var errInfo string = "git pull error: "+string(output)
				common.Logger(common.LOG_WARNING, errInfo)
				return common.Object2JsonStr(ResponseMsg{5, errInfo, nil})
			}

			fileBytes, err := ioutil.ReadFile(BUILD_PATH+"/index.json")
			if err != nil {
				var errInfo string = "read build.json faild"
				common.Logger(common.LOG_WARNING, errInfo)
				return common.Object2JsonStr(ResponseMsg{7, errInfo, nil})
			}

			fileStr := string(fileBytes)
			j, err := simplejson.NewJson([]byte(fileStr))
			if err != nil {
				var errInfo string = "parse build.json 's json faild,"+err.Error()
				common.Logger(common.LOG_WARNING, errInfo)
				return common.Object2JsonStr(ResponseMsg{8, "parse build.json 's json faild,"+err.Error(), nil})
			}
			access, _ := j.Get("access").StringArray()
			userExists := false

			for _, v := range access {
				if v == req.Form.Get("username") {
					userExists = true
					break
				}
			}

			if !userExists {
				var errInfo string = req.Form.Get("username")+" isn't in build.json 's access"
				common.Logger(common.LOG_WARNING, errInfo)
				return common.Object2JsonStr(ResponseMsg{6, errInfo, nil})
			}
			common.Logger(common.LOG_INFO, "git pull build.json success")

			if isUploading(req.Form.Get("username"), req.Form.Get("module")) {
				recordInfo, _ := ioutil.ReadFile(RECORD_PATH)
				recordInfos := strings.Split(string(recordInfo), "|")
				common.Logger(common.LOG_WARNING, "uploader conflict: " + recordInfos[0]+" <--> " + req.Form.Get("username"))
				return common.Object2JsonStr(ResponseMsg{1, "if you are not the uploader of " + recordInfos[1] + ", plz concat " + recordInfos[0]+",otherwise plz wait...", nil})

			}else {
				backPath := TMP_PATH_PREFIX+"/"+req.Form.Get("module")
				_, err := os.Stat(backPath)
				if os.IsNotExist(err) {
					os.MkdirAll(backPath, 0777)
				}

				common.Logger(common.LOG_INFO, req.Form.Get("username") + " is uploading " +  req.Form.Get("module") + " to online server")
				return common.Object2JsonStr(ResponseMsg{0, "success", nil})
			}

		}else if (req.Form.Get("type") == "2") {
			os.Remove(RECORD_PATH)
			common.Logger(common.LOG_INFO, "unlink "+RECORD_PATH+" success")
			return common.Object2JsonStr(ResponseMsg{0, "success", nil})
		}
	}else if req.MultipartForm.Value["to"][0] != "" {
		_, err := os.Stat(RECORD_PATH)
		if os.IsNotExist(err) {
			return "0"
		}else {
			to, _ := url.QueryUnescape(req.MultipartForm.Value["to"][0])
			files := req.MultipartForm.File
			fi, err := os.Stat(to)

			if ((err == nil && os.IsExist(err)) && fi.IsDir()) || len(files) == 0 {
				res.WriteHeader(500)
				return "1"
			}else {
				f := files["file"][0]
				return strconv.Itoa(move2Tmp(to, f) & move2Server(to, f))
			}
		}
	}

	return `I\'m ready for that, you know.`
}

func isUploading(username string, module string) bool {
	_, err := os.Stat(RECORD_PATH)
	if os.IsNotExist(err) {
		content := username+"|"+module+"|"+strconv.Itoa(int(time.Now().Unix()))
		err := ioutil.WriteFile(RECORD_PATH, []byte(content), 0777)
		if err != nil {
			return false
		}
	}else {
		recordInfo, _ := ioutil.ReadFile(RECORD_PATH)
		recordInfos := strings.Split(string(recordInfo), "|")
		return !(recordInfos[0] == username && recordInfos[1] == module)
	}

	return true
}

func move2Tmp(path string, fileHeader *multipart.FileHeader) int {
	recordInfo, _ := ioutil.ReadFile(RECORD_PATH)
	recordInfos := strings.Split(string(recordInfo), "|")
	dirpath := TMP_PATH_PREFIX+"/"+recordInfos[1]+"/"+recordInfos[2]
	backpath := dirpath+"/"+path
	_, err := os.Stat(dirpath)
	if os.IsNotExist(err) {
		os.MkdirAll(dirpath, 0777)
	}

	dirname := filepath.Dir(backpath)
	_, err = os.Stat(dirname)
	if os.IsNotExist(err) {
		os.MkdirAll(dirname, 0777)
	}

	configAppendFile(backpath, path, dirpath)

	upfile, err := fileHeader.Open()
	defer upfile.Close()

	_, err = moveUploadFile(backpath, upfile)
	if err != nil {
		return 1
	}else {
		return 0
	}
}

func move2Server(path string, fileHeader *multipart.FileHeader) int {
	_, err := os.Stat(path)
	if err == nil || os.IsExist(err) {
		os.Remove(path)
	}else {
		dirpath := filepath.Dir(path)
		_, err = os.Stat(dirpath)
		if os.IsNotExist(err) {
			os.MkdirAll(dirpath, 0777)
		}
	}

	upfile, err := fileHeader.Open()
	defer upfile.Close()

	_, err = moveUploadFile(path, upfile)

	if err != nil {
		return 1
	}else {
		return 0
	}
}

func configAppendFile(back string, to string, dir string) {
	configPath := dir+"/map.txt"
	file, _ := os.OpenFile(configPath, os.O_RDWR|os.O_APPEND|os.O_CREATE, 0777)
	defer file.Close()

	file.WriteString(to+"->"+back+"\n")
}


